package dkr.core.serialize;

import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import dkr.core.cache.FixedCacheMap;


/**
 * @author xuyd
 *
 */
public class SerializeTypeHandle {
	private SerializeTypeHandle parent;
	private SerializeType serializeType;
	private Type genericType;
	private Class<?> rawType;
	private SerializeTypeHandle left;
	private SerializeTypeHandle right;
	private boolean valid = true;
	private String describer;
	
	private static FixedCacheMap<String, SerializeTypeHandle> handlers;
	private static FixedCacheMap<String, SerializeTypeHandle> sysHandlers;
	private static Map<String, SerializeType> simpleTypes;
	private static Map<String, SerializeType> containerInterfaces;
	static{
		handlers = new FixedCacheMap<String, SerializeTypeHandle>(300);
		sysHandlers = new FixedCacheMap<String, SerializeTypeHandle>(30);
		
		simpleTypes = new HashMap<String, SerializeType>();
		simpleTypes.put(Boolean.class.getName(), SerializeType.BOOLEAN);
		simpleTypes.put(Byte.class.getName(), SerializeType.BYTE);
		simpleTypes.put(Short.class.getName(), SerializeType.SHORT);
		simpleTypes.put(Integer.class.getName(), SerializeType.INTEGER);
		simpleTypes.put(Long.class.getName(), SerializeType.LONG);
		simpleTypes.put(BigInteger.class.getName(), SerializeType.BIGINTERGER);
		simpleTypes.put(BigDecimal.class.getName(), SerializeType.BIGDECIMAL);
		simpleTypes.put(Float.class.getName(), SerializeType.FLOAT);
		simpleTypes.put(Double.class.getName(), SerializeType.DOUBLE);
		simpleTypes.put(Character.class.getName(), SerializeType.CHARACTER);
		simpleTypes.put(String.class.getName(), SerializeType.STRING);
		simpleTypes.put(Date.class.getName(), SerializeType.DATE);
		simpleTypes.put(java.sql.Date.class.getName(), SerializeType.SQLDATE);
		simpleTypes.put(Time.class.getName(), SerializeType.SQLTIME);
		simpleTypes.put(Timestamp.class.getName(), SerializeType.SQLTIMESTAMP);
		
		containerInterfaces = new HashMap<String, SerializeType>();
		containerInterfaces.put(List.class.getName(), SerializeType.LIST);
		containerInterfaces.put(Iterator.class.getName(), SerializeType.ITERATOR);
		containerInterfaces.put(Iterable.class.getName(), SerializeType.ITERABLE);
		containerInterfaces.put(Map.class.getName(), SerializeType.MAP);
	}
	
	private static SerializeType getContainerSerializeTypeByInterface(Class<?> clazz){
		SerializeType type = containerInterfaces.get(clazz.getName());
		if(type != null)
			return type;
		Class<?>[] inters = clazz.getInterfaces();
		if(inters != null && inters.length > 0){
			for(Class<?> item : inters){
				String itemName = item.getName();
				if(containerInterfaces.containsKey(itemName)){
					type = containerInterfaces.get(itemName);
					break;
				}
			}
		}
		return type;
	}
	
	public static SerializeTypeHandle getHandler(Type type){
		if(type == null)
			return null;
		
		SerializeTypeHandle handler = null;
		String key = type.toString();
		if(key.startsWith("java.")){
			handler = handlers.get(key);
			if(handler == null){
				handler = new SerializeTypeHandle(type);
				if(handler.valid){
					handlers.put(key, handler);
				}
				else{
					handler = null;
				}
			}
		}
		else{
			handler = sysHandlers.get(key);
			if(handler == null){
				handler = new SerializeTypeHandle(type);
				if(handler.valid){
					sysHandlers.put(key, handler);
				}
				else{
					handler = null;
				}
			}
		}

		return handler;
	}
	
	private SerializeTypeHandle(){
		
	}
	
	private SerializeTypeHandle(Type type){
		this(null, type);
	}
	
	private SerializeTypeHandle(SerializeTypeHandle parent, Type type){
		this.parent = parent;
		if(type == null){
			this.describer = "NULL";
			System.err.printf("The type [NULL] can't be serialized\r\n");
			doInvalid();
		}
		else{
			this.describer = type.toString();
			this.genericType = type;
			init();
		}
	}
	
	private void doInvalid(){
		this.valid = false;
		if(parent != null)
			parent.doInvalid();
	}
	
	public static SerializeTypeHandle getSerializeType(Class<?> clazz){
		SerializeTypeHandle handle = new SerializeTypeHandle();
		if(clazz.isPrimitive()){
			if(Boolean.TYPE == clazz){
				handle.serializeType = SerializeType.BOOLEAN;
				handle.rawType = Boolean.class;
			}
			else if(Byte.TYPE == clazz){
				handle.serializeType = SerializeType.BYTE;
				handle.rawType = Byte.class;
			}
			else if(Short.TYPE == clazz){
				handle.serializeType = SerializeType.SHORT;
				handle.rawType = Short.class;
			}
			else if(Integer.TYPE == clazz){
				handle.serializeType = SerializeType.INTEGER;
				handle.rawType = Integer.class;
			}
			else if(Long.TYPE == clazz){
				handle.serializeType = SerializeType.LONG;
				handle.rawType = Long.class;
			}
			else if(Float.TYPE == clazz){
				handle.serializeType = SerializeType.FLOAT;
				handle.rawType = Float.class;
			}
			else if(Double.TYPE == clazz){
				handle.serializeType = SerializeType.DOUBLE;
				handle.rawType = Double.class;
			}
			else if(Character.TYPE == clazz){
				handle.serializeType = SerializeType.CHARACTER;
				handle.rawType = Character.class;
			}
		}
		else if(clazz.isArray()){
			handle.serializeType = SerializeType.ARRAY;
			Class<?> componentType = clazz.getComponentType();
			if(PHPSerializer.isPHPSerializable(componentType)){
				handle.left = new SerializeTypeHandle();
				handle.left.parent = handle;
				handle.left.serializeType = SerializeType.OBJECT;
				handle.left.genericType = componentType;
				handle.left.rawType = componentType;
			}
			else{
				handle.left = getHandler(componentType);
			}
		}
		else if(PHPSerializer.isPHPSerializable(clazz)){
			handle.serializeType = SerializeType.OBJECT;
			handle.rawType = clazz;
		}
		else{
			SerializeType retType = simpleTypes.get(clazz.getName());
			handle.rawType = clazz;
			if(retType != null){
				handle.serializeType = retType;
			}
			else{
				retType = getContainerSerializeTypeByInterface(clazz);
				if(retType != null){
					handle.serializeType = retType;
				}
				else{
					handle.serializeType = SerializeType.OBJECT;
				}
			}
		}
		return handle;
	}
	
	private void init(){
		Type type = this.genericType;
		if(type instanceof Class<?>){
			Class<?> clazz = (Class<?>)type;
			if(clazz.isPrimitive()){
				if(Boolean.TYPE == clazz){
					this.serializeType = SerializeType.BOOLEAN;
					this.rawType = Boolean.class;
				}
				else if(Byte.TYPE == clazz){
					this.serializeType = SerializeType.BYTE;
					this.rawType = Byte.class;
				}
				else if(Short.TYPE == clazz){
					this.serializeType = SerializeType.SHORT;
					this.rawType = Short.class;
				}
				else if(Integer.TYPE == clazz){
					this.serializeType = SerializeType.INTEGER;
					this.rawType = Integer.class;
				}
				else if(Long.TYPE == clazz){
					this.serializeType = SerializeType.LONG;
					this.rawType = Long.class;
				}
				else if(Float.TYPE == clazz){
					this.serializeType = SerializeType.FLOAT;
					this.rawType = Float.class;
				}
				else if(Double.TYPE == clazz){
					this.serializeType = SerializeType.DOUBLE;
					this.rawType = Double.class;
				}
				else if(Character.TYPE == clazz){
					this.serializeType = SerializeType.CHARACTER;
					this.rawType = Character.class;
				}
			}
			else if(clazz.isArray()){
				this.serializeType = SerializeType.ARRAY;
				Class<?> componentType = clazz.getComponentType();
				if(PHPSerializer.isPHPSerializable(componentType)){
					this.left = new SerializeTypeHandle();
					this.left.parent = this;
					this.left.serializeType = SerializeType.OBJECT;
					this.left.genericType = componentType;
					this.left.rawType = componentType;
				}
				else{
					this.left = getHandler(componentType);
				}
			}
			else if(PHPSerializer.isPHPSerializable(clazz)){
				this.serializeType = SerializeType.OBJECT;
				this.rawType = clazz;
			}
			else{
				SerializeType retType = simpleTypes.get(clazz.getName());
				this.rawType = clazz;
				if(retType != null){
					this.serializeType = retType;
				}
				else{
					retType = getContainerSerializeTypeByInterface(clazz);
					if(retType != null){
						this.serializeType = retType;
					}
					else{
						this.serializeType = SerializeType.OBJECT;
					}
				}
			}
		}
		else if(type instanceof ParameterizedType){
			ParameterizedType ptype = (ParameterizedType)type;
			Type rtype = ptype.getRawType();
			if(rtype instanceof Class<?>){
				Class<?> clazz = (Class<?>)rtype;
				this.rawType = clazz;
				SerializeType retType = getContainerSerializeTypeByInterface(clazz);
				if(retType != null){
					switch (retType) {
					case LIST:
					case ITERABLE:
					case ITERATOR:
						this.serializeType = retType;
						this.left = new SerializeTypeHandle(this, ptype.getActualTypeArguments()[0]);
						break;
					case MAP:
						this.serializeType = retType;
						this.left = new SerializeTypeHandle(this, ptype.getActualTypeArguments()[0]);
						this.right = new SerializeTypeHandle(this, ptype.getActualTypeArguments()[1]);
						break;
					default:
						break;
					}
				}
			}
		}
		else if(type instanceof GenericArrayType){
			this.serializeType = SerializeType.ARRAY;
			GenericArrayType atype = (GenericArrayType)type;
			Type ctype = atype.getGenericComponentType();
			if(ctype instanceof ParameterizedType){
				this.left = new SerializeTypeHandle(this, ctype);
			}
		}
		if(this.serializeType == null){
			System.err.printf("The type [%s] can't be serialized\r\n", type.toString());
			doInvalid();
		}
	}

	public SerializeType getSerializeType() {
		return serializeType;
	}

	@Override
	public String toString() {
		return this.serializeType.name() + "[" + describer + "]";
	}
	
	public Object serialize(Object obj){
		Object ret = null;
		if(obj == null){
			switch (this.serializeType) {
			case BOOLEAN:
				ret = false;
				break;
			case BYTE:
			case SHORT:
			case INTEGER:
				ret = 0;
				break;
			case LONG:
				ret = 0L;
				break;
			case FLOAT:
			case DOUBLE:
				ret = 0D;
				break;
			case CHARACTER:
				char c = 0;
				ret = String.valueOf(c);
				break;
			default:
				ret = null;
				break;
			}
		}
		else{
			switch(this.serializeType){
			case BOOLEAN:
				ret = serializeBoolean(obj);
				break;
			case BYTE:
				ret = serializeByte(obj);
				break;
			case SHORT:
				ret = serializeShort(obj);
				break;
			case INTEGER:
				ret = serializeInteger(obj);
				break;
			case LONG:
				ret = serializeLong(obj);
				break;
			case BIGINTERGER:
				ret = serializeBigInteger(obj);
				break;
			case FLOAT:
				ret = serializeFloat(obj);
				break;
			case DOUBLE:
				ret = serializeDouble(obj);
				break;
			case BIGDECIMAL:
				ret = serializeBigDecimal(obj);
				break;
			case CHARACTER:
				ret = serializeCharacter(obj);
				break;
			case STRING:
				ret = serializeString(obj);
				break;
			case DATE:
				ret = serializeDate(obj);
				break;
			case SQLDATE:
				ret = serializeSqlDate(obj);
				break;
			case SQLTIME:
				ret = serializeSqlTime(obj);
				break;
			case SQLTIMESTAMP:
				ret = serializeSqlTimestamp(obj);
				break;
			case ARRAY:
				ret = serializeArray(obj);
				break;
			case LIST:
				ret = serializeList(obj);
				break;
			case ITERABLE:
				ret = serializeIterable(obj);
				break;
			case ITERATOR:
				ret = serializeIterator(obj);
				break;
			case MAP:
				ret = serializeMap(obj);
				break;
			case OBJECT:
				ret = serializeMapStruct(obj);
				break;				
			default:
				ret = serializeObject(obj);
				break;
			}
		}
		return ret;
	}
	
	private Boolean serializeBoolean(Object obj){
		return (Boolean)obj;
	}

	private Integer serializeByte(Object obj){
		return ((Byte)obj).intValue();
	}
	
	private Integer serializeShort(Object obj){
		return ((Short)obj).intValue();
	}
	
	private Integer serializeInteger(Object obj){
		return (Integer)obj;
	}
	
	private Long serializeLong(Object obj){
		return (Long)obj;
	}
	
	private Long serializeBigInteger(Object obj){
		return ((BigInteger)obj).longValue();
	}
	
	private Double serializeFloat(Object obj){
		return ((Float)obj).doubleValue();
	}
	
	private Double serializeDouble(Object obj){
		return (Double)obj;
	}
	
	private Double serializeBigDecimal(Object obj){
		return ((BigDecimal)obj).doubleValue();
	}
	
	private String serializeCharacter(Object obj){
		return ((Character)obj).toString();
	}
	
	private String serializeString(Object obj){
		return (String)obj;
	}
	
	private Date serializeDate(Object obj){
		return (Date)obj;
	}
	
	private Date serializeSqlDate(Object obj){
		return new Date(((java.sql.Date)obj).getTime());
	}
	
	private Date serializeSqlTime(Object obj){
		return new Date(((Time)obj).getTime());
	}
	
	private Date serializeSqlTimestamp(Object obj){
		return new Date(((Timestamp)obj).getTime());
	}
	
	private List<Object> serializeArray(Object obj){
		List<Object> results = new ArrayList<Object>();
		int size = 0;
		try{
			size = Array.getLength(obj);
		}
		catch(Exception e){
			e.printStackTrace();
		}
		if(size == 0)
			return results;
		
		SerializeTypeHandle itemHandle = this.left;
		if(itemHandle == null)
			return results;
		for(int i = 0; i < size; i++){
			Object item = Array.get(obj, i);
			results.add(itemHandle.serialize(item));
		}
		return results;
	}
	
	@SuppressWarnings("unchecked")
	private List<Object> serializeList(Object obj){
		List<Object> results = new ArrayList<Object>();
		if(!(obj instanceof List))
			return results;
		
		SerializeTypeHandle itemHandle = this.left;
		if(itemHandle == null)
			return results;
		
		List<Object> list = (List<Object>)obj;
		if(list.isEmpty())
			return results;
		
		for(Object item : list){
			results.add(itemHandle.serialize(item));
		}
		return results;
	}
	
	@SuppressWarnings("unchecked")
	private List<Object> serializeIterable(Object obj){
		List<Object> results = new ArrayList<Object>();
		if(!(obj instanceof Iterable))
			return results;
		
		SerializeTypeHandle itemHandle = this.left;
		if(itemHandle == null)
			return results;
		
		Iterable<Object> it = (Iterable<Object>)obj;
		Iterator<Object> itor = it.iterator();
		while(itor.hasNext()){
			results.add(itemHandle.serialize(itor.next()));
		}
		return results;
	}
	
	@SuppressWarnings("unchecked")
	private List<Object> serializeIterator(Object obj){
		List<Object> results = new ArrayList<Object>();
		if(!(obj instanceof Iterator))
			return results;
		
		SerializeTypeHandle itemHandle = this.left;
		if(itemHandle == null)
			return results;
		
		Iterator<Object> itor = (Iterator<Object>)obj;
		while(itor.hasNext()){
			results.add(itemHandle.serialize(itor.next()));
		}
		return results;
	}
	
	@SuppressWarnings("unchecked")
	private Map<Object, Object> serializeMap(Object obj){
		Map<Object, Object> results = new HashMap<Object, Object>();
		if(!(obj instanceof Map))
			return results;
		if(this.left == null || this.right == null)
			return results;
		
		Map<Object, Object> map = (Map<Object, Object>)obj;
		if(map.isEmpty())
			return results;
		
		for(Object key : map.keySet()){
			Object retKey = this.left.serialize(key);
			if(retKey != null){
				Object val = map.get(retKey);
				results.put(retKey, this.right.serialize(val));
			}
		}
		return results;
	}
	
	private Object serializeMapStruct(Object obj){
		return SerializeObjectHandle.toSerializable(obj);
	}
	
	private String serializeObject(Object obj){
		return obj.toString();
	}
	
	public Object unserialize(Object obj){
		return unserialize(obj, this.serializeType);
	}
	
	@SuppressWarnings("unchecked")
	private Object unserialize(Object obj, SerializeType serializeType){
		Object ret = null;
		if(obj == null){
			switch (serializeType) {
			case BOOLEAN:
				ret = Boolean.FALSE;
				break;
			case BYTE:
				ret = new Integer(0).byteValue();
				break;
			case SHORT:
				ret = new Integer(0).shortValue();
				break;
			case INTEGER:
				ret = 0;
				break;
			case LONG:
				ret = 0L;
				break;
			case FLOAT:
				ret = 0F;
				break;
			case DOUBLE:
				ret = 0D;
				break;
			case CHARACTER:
				char c = 0;
				ret = Character.valueOf(c);
				break;
			default:
				ret = null;
				break;
			}
		}
		else{
			switch (serializeType) {
			case BOOLEAN:
				ret = unserializeBoolean(obj);
				break;
			case BYTE:
				ret = unserializeByte(obj);
				break;
			case SHORT:
				ret = unserializeShort(obj);
				break;
			case INTEGER:
				ret = unserializeInteger(obj);
				break;
			case LONG:
				ret = unserializeLong(obj);
				break;
			case BIGINTERGER:
				ret = unserializeBigInteger(obj);
				break;
			case FLOAT:
				ret = unserializeFloat(obj);
				break;
			case DOUBLE:
				ret = unserializeDouble(obj);
				break;
			case BIGDECIMAL:
				ret = unserializeBigDecimal(obj);
				break;
			case CHARACTER:
				ret = unserializeCharacter(obj);
				break;
			case STRING:
				ret = unserializeString(obj);
				break;
			case DATE:
				ret = unserializeDate(obj);
				break;
			case SQLDATE:
				ret = unserializeSqlDate(obj);
				break;
			case SQLTIME:
				ret = unserializeSqlTime(obj);
				break;
			case SQLTIMESTAMP:
				ret = unserializeSqlTimestamp(obj);
				break;
			case ARRAY:
				if(obj instanceof List){
					ret = unserializeArray((List<Object>)obj);
				}
				break;
			case LIST:
				if(obj instanceof List){
					ret = unserializeList((List<Object>)obj);
				}
				break;
			case ITERABLE:
				if(obj instanceof List){
					ret = unserializeIterable((List<Object>)obj);
				}
				break;
			case ITERATOR:
				if(obj instanceof List){
					ret = unserializeIterator((List<Object>)obj);
				}
				break;
			case MAP:
				if(obj instanceof Map){
					ret = unserializeMap((Map<Object,Object>)obj);
				}
				break;
			case OBJECT:
				if(obj instanceof Map){
					Map<String, Object> map = null;
					try{
						map = (Map<String, Object>)obj;
					}
					catch (Exception e) {
						
					}
					if(map != null)
						ret = unserializeMapStruct(map);
				}
				else{
					ret = obj;
				}
				break;
			default:
				ret = unserializeObject(obj);
				break;
			}
		}
		return ret;
	}
	
	private Boolean unserializeBoolean(Object obj){
		Boolean ret = false;
		if(obj instanceof Boolean){
			ret = (Boolean)obj;
		}
		else if(obj instanceof String){
			String key = obj.toString().trim().toLowerCase();
			if("true".equals(key) || "1".equals(key) || "y".equals(key) || "yes".equals(key) || "ok".equals(key))
				ret = true;
		}
		else{
			ret = toNumber(obj) != 0;
		}
		return ret;
	}

	private Byte unserializeByte(Object obj){
		Byte ret = 0;
		if(obj instanceof Integer)
			ret = ((Integer)obj).byteValue();
		else
			ret = ((Integer)toNumber(obj).intValue()).byteValue();
		return ret;
	}
	
	private Short unserializeShort(Object obj){
		Integer val = 0;
		if(obj instanceof Integer)
			val = (Integer)obj;
		else
			val = toNumber(obj).intValue();
		return val.shortValue();
	}
	
	private Integer unserializeInteger(Object obj){
		Integer val = 0;
		if(obj instanceof Integer)
			val = (Integer)obj;
		else
			val = toNumber(obj).intValue();
		return val;
	}
	
	private Long unserializeLong(Object obj){
		Long ret = 0L;
		if(obj instanceof Long)
			ret = (Long)obj;
		else if(obj instanceof Integer)
			ret = ((Integer)obj).longValue();
		else if(obj instanceof Double)
			ret = ((Double)obj).longValue();
		else
			ret = toNumber(obj).longValue();
		return ret;
	}
	
	private BigInteger unserializeBigInteger(Object obj){
		return BigInteger.valueOf(unserializeLong(obj));
	}
	
	private Float unserializeFloat(Object obj){
		return unserializeDouble(obj).floatValue();
	}
	
	private Double unserializeDouble(Object obj){
		Double ret = 0D;
		if(obj instanceof Double)
			ret = (Double)obj;
		else if(obj instanceof Integer)
			ret = ((Integer)obj).doubleValue();
		else if(obj instanceof Long)
			ret = ((Long)obj).doubleValue();
		else
			ret = toNumber(obj);
		return ret;
	}
	
	private BigDecimal unserializeBigDecimal(Object obj){
		return BigDecimal.valueOf(unserializeDouble(obj));
	}
	
	private Character unserializeCharacter(Object obj){
		String str = obj.toString();
		if(str.isEmpty()){
			char c = 0;
			return c;
		}
		else{
			return str.charAt(0);
		}
	}
	
	private String unserializeString(Object obj){
		return obj.toString();
	}
	
	private Date unserializeDate(Object obj){
		long t = unserializeLong(obj);
		if(t > 0)
			return new Date(t);
		else
			return null;
	}
	
	private java.sql.Date unserializeSqlDate(Object obj){
		long t = unserializeLong(obj);
		if(t > 0)
			return new java.sql.Date(t);
		else
			return null;
	}
	
	private Time unserializeSqlTime(Object obj){
		long t = unserializeLong(obj);
		if(t > 0)
			return new Time(t);
		else
			return null;
	}
	
	private Timestamp unserializeSqlTimestamp(Object obj){
		long t = unserializeLong(obj);
		if(t > 0)
			return new Timestamp(t);
		else
			return null;
	}
	
	private Object unserializeMapStruct(Map<String, Object> map){
		if(this.rawType == null)
			return null;
		else
			return SerializeObjectHandle.toBean(this.rawType, map);
	}
	
	private Object unserializeArray(List<Object> list){
		Class<?> constructor = getConstructClass(this);
		if(constructor == null)
			return null;
		int size = list.size();
		
		Object ret = null;
		try{
			ret = Array.newInstance(constructor, size);
		}
		catch(Exception e){
			e.printStackTrace();
		}
		if(ret == null || size == 0)
			return ret;
		
		for(int i = 0; i < size; i++){
			Array.set(ret, i, this.left.unserialize(list.get(i)));
		}
		
		return ret;
	}
	
	@SuppressWarnings("unchecked")
	private Object unserializeList(List<Object> list){
		Class<?> constructor = getConstructClass(this);
		if(constructor == null)
			return null;
		int size = list.size();
		
		Object ret = null;
		try{
			ret = constructor.newInstance();
		}
		catch(Exception e){
			e.printStackTrace();
		}
		if(ret == null || size == 0)
			return ret;
		List<Object> retlist = (List<Object>)ret;
		for(Object item : list){
			retlist.add(this.left.unserialize(item));
		}
		return retlist;
	}
	
	@SuppressWarnings("unchecked")
	private Object unserializeIterable(List<Object> list){
		Class<?> constructor = getConstructClass(this);
		if(constructor == null)
			return null;
		int size = list.size();
		
		Object ret = null;
		try{
			ret = constructor.newInstance();
		}
		catch(Exception e){
			e.printStackTrace();
		}
		if(ret == null || size == 0)
			return ret;
		SimpleIterable<Object> it = (SimpleIterable<Object>)ret;
		for(Object item : list){
			it.add(this.left.unserialize(item));
		}
		return it;
	}
	
	@SuppressWarnings("unchecked")
	private Object unserializeIterator(List<Object> list){
		Class<?> constructor = getConstructClass(this);
		if(constructor == null)
			return null;
		int size = list.size();
		
		Object ret = null;
		try{
			ret = constructor.newInstance();
		}
		catch(Exception e){
			e.printStackTrace();
		}
		if(ret == null || size == 0)
			return ret;
		SimpleIterator<Object> it = (SimpleIterator<Object>)ret;
		for(Object item : list){
			it.add(this.left.unserialize(item));
		}
		return it;
	}
	
	@SuppressWarnings("unchecked")
	private Object unserializeMap(Map<Object, Object> map){
		Class<?> constructor = getConstructClass(this);
		if(constructor == null || this.right == null)
			return null;
		int size = map.size();
		
		Object ret = null;
		try{
			ret = constructor.newInstance();
		}
		catch(Exception e){
			e.printStackTrace();
		}
		if(ret == null || size == 0)
			return ret;
		
		Map<Object, Object> retMap = (Map<Object, Object>)ret;
		for(Object key : map.keySet()){
			Object retKey = this.left.unserialize(key);
			if(retKey == null)
				continue;
			retMap.put(retKey, this.right.unserialize(map.get(key)));
		}
		
		return retMap;
	}
	
	private Object unserializeObject(Object obj){
		return null;
	}
	
	private Double toNumber(Object value){
		Double ret = 0D;
		try{
			char[] ary = value.toString().toCharArray();
			String val = "";
			boolean skip = true;
			int pointCount = 0;
			for(int i = 0; i < ary.length; i++){
				if(ary[i] == '.'){
					if(pointCount > 0 || i == ary.length -1)
						break;
					if(ary[i+1] >= '0' && ary[i+1] <= '9'){
						skip = false;
						val += ary[i];
						++pointCount;
					}
				}
				else if(ary[i] >= '0' && ary[i] <= '9'){
					skip = false;
					val += ary[i];
				}
				else{
					if(!skip)
						break;
				}
			}
			if(!val.isEmpty()){
				ret = Double.parseDouble(val);
			}
		}
		catch(Exception e){
			e.printStackTrace();
		}
		if(ret == null)
			ret = 0D;
		return ret;
	}
	
	private static Class<?> getConstructClass(SerializeTypeHandle handle){
		Class<?> constructor = null;
		switch(handle.serializeType){
		case BOOLEAN:
		case BYTE:
		case SHORT:
		case INTEGER:
		case LONG:
		case BIGINTERGER:
		case FLOAT:
		case DOUBLE:
		case BIGDECIMAL:
		case CHARACTER:
		case STRING:
		case DATE:
		case SQLDATE:
		case SQLTIME:
		case SQLTIMESTAMP:
		case OBJECT:
			constructor = handle.rawType;
			break;
		case ARRAY:
			if(handle.left != null){
				constructor = getContainerConstructClass(handle.left);
			}
			break;
		case LIST:
		case ITERABLE:
		case ITERATOR:
		case MAP:
			constructor = getContainerConstructClass(handle);
			break;
		default:
			break;
		}
		return constructor;
	}
	
	private static Class<?> getContainerConstructClass(SerializeTypeHandle handle){
		if(handle == null || handle.rawType == null)
			return null;
		Class<?> ret = handle.rawType;
		switch (handle.serializeType) {
		case ARRAY:
			ret = getContainerConstructClass(handle.left);
			break;
		case LIST:
			if(handle.rawType.isInterface() || Modifier.isAbstract(handle.rawType.getModifiers())){
				ret = ArrayList.class;
			}
			break;
		case ITERABLE:
			if(Iterable.class.getName().equals(handle.rawType.getName())){
				ret = SimpleIterable.class;
			}
			else {
				ret = null;
			}
			break;
		case ITERATOR:
			if(Iterator.class.getName().equals(handle.rawType.getName())){
				ret = SimpleIterator.class;
			}
			else{
				ret = null;
			}
			break;
		case MAP:
			if(handle.rawType.isInterface() || Modifier.isAbstract(handle.rawType.getModifiers())){
				ret = HashMap.class;
			}
			break;
		default:
			break;
		}
		return ret;
	}
}
